Skip to content

fix: remove unsupported fields from requests to Bedrock#225

Merged
pawbana merged 2 commits into
mainfrom
pb/bedrock-adaptive-thinking-fix
Mar 26, 2026
Merged

fix: remove unsupported fields from requests to Bedrock#225
pawbana merged 2 commits into
mainfrom
pb/bedrock-adaptive-thinking-fix

Conversation

@pawbana
Copy link
Copy Markdown
Contributor

@pawbana pawbana commented Mar 19, 2026

This PR removes unsupported fields from requests to Bedrock.
Adaptive thinking field is replaced for models that don't support with type: enabled + budget_tokens: N combination.
budget_tokens value is calculated as a ratio of max_tokens.
Ratio depends on output_config.effort value, used the same ratio values as OpenRouter does: https://openrouter.ai/docs/guides/best-practices/reasoning-tokens#reasoning-effort-level

Fixes: #219

@pawbana pawbana marked this pull request as ready for review March 19, 2026 21:56
@pawbana pawbana force-pushed the pb/bedrock-adaptive-thinking-fix branch from 7d8c1ae to dcc3668 Compare March 20, 2026 11:15
@pawbana pawbana changed the title fix: remove adaptive thinking from Bedrock models that don't support it fix: remove unsupported fields from requests to Bedrock Mar 20, 2026
Comment thread intercept/messages/base.go
Comment thread intercept/messages/reqpayload.go
Comment thread intercept/messages/reqpayload.go Outdated
Comment thread intercept/messages/reqpayload.go Outdated
Comment thread intercept/messages/reqpayload.go Outdated
@pawbana pawbana force-pushed the pb/bedrock-adaptive-thinking-fix branch 2 times, most recently from 39ebebb to 20254b5 Compare March 24, 2026 11:54
@pawbana pawbana requested a review from dannykopping March 26, 2026 09:19
@pawbana pawbana force-pushed the pb/messages-remove-paramswrap branch from 41fbe48 to 6f57430 Compare March 26, 2026 16:12
@pawbana pawbana force-pushed the pb/bedrock-adaptive-thinking-fix branch from 20254b5 to 61e7146 Compare March 26, 2026 16:12
Copy link
Copy Markdown
Contributor Author

pawbana commented Mar 26, 2026

Merge activity

  • Mar 26, 4:28 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Mar 26, 4:30 PM UTC: Graphite rebased this pull request as part of a merge.
  • Mar 26, 4:33 PM UTC: @pawbana merged this pull request with Graphite.

@pawbana pawbana changed the base branch from pb/messages-remove-paramswrap to graphite-base/225 March 26, 2026 16:28
@pawbana pawbana changed the base branch from graphite-base/225 to main March 26, 2026 16:28
@pawbana pawbana force-pushed the pb/bedrock-adaptive-thinking-fix branch from 61e7146 to 6987152 Compare March 26, 2026 16:30
@pawbana pawbana merged commit 1a3a7f3 into main Mar 26, 2026
5 checks passed
pawbana added a commit that referenced this pull request Mar 27, 2026
This PR removes unsupported fields from requests to Bedrock.
Adaptive thinking field is replaced for models that don't support with `type: enabled` + `budget_tokens: N` combination.
`budget_tokens` value is calculated as a ratio of `max_tokens`.
Ratio depends on `output_config.effort` value, used the same ratio values as OpenRouter does: https://openrouter.ai/docs/guides/best-practices/reasoning-tokens#reasoning-effort-level

Fixes: #219
pawbana added a commit that referenced this pull request Mar 30, 2026
* chore: remove SDK struct usage from requests in messages API (#218)

Replaces MessageNewParamsWrapper that wrapped anthropic.MessageNewParams
with MessagesRequestPayload that operates on raw bytes.

* fix: remove unsupported fields from requests to Bedrock (#225)

This PR removes unsupported fields from requests to Bedrock.
Adaptive thinking field is replaced for models that don't support with `type: enabled` + `budget_tokens: N` combination.
`budget_tokens` value is calculated as a ratio of `max_tokens`.
Ratio depends on `output_config.effort` value, used the same ratio values as OpenRouter does: https://openrouter.ai/docs/guides/best-practices/reasoning-tokens#reasoning-effort-level

Fixes: #219

* fix: filter unsupported Anthropic-Beta headers from Bedrock (#226)

Removes headers from requests to Bedrock that are unsupported.

Fixes: #221
dannykopping added a commit to coder/coder that referenced this pull request May 14, 2026
…e for Bedrock Opus 4.7+

Claude Opus 4.7 (and future adaptive-only Bedrock models) reject the legacy
thinking.type "enabled" + budget_tokens shape with a 400. Claude Code falls
back to that shape when it cannot read the upstream model's capability
metadata, which is exactly the case when AI Bridge sits between the client
and Bedrock.

This is the symmetric counterpart to the adaptive -> enabled conversion
added in coder/aibridge#225 for older Bedrock models. The new conversion is
gated on a bedrockModelRequiresAdaptiveThinking helper that matches Opus
4.7 model IDs (and ARN-style application inference profile names that
include the model ID).

The effort level is derived from the original budget_tokens / max_tokens
ratio using the midpoints of the forward mapping's anchor ratios, so a
payload that round-trips through both conversions lands on the same effort
level it started with. An explicit output_config.effort already present in
the request is preserved.

Adaptive-only models support output_config natively (no beta flag), so the
field-strip pass is updated to exempt output_config for those models via a
new variadic exemptFields parameter on removeUnsupportedBedrockFields.

Fixes coder/aibridge#280
dannykopping added a commit to coder/coder that referenced this pull request May 14, 2026
…e for Bedrock Opus 4.7+

Claude Opus 4.7 (and future adaptive-only Bedrock models) reject the legacy
thinking.type "enabled" + budget_tokens shape with a 400. Claude Code falls
back to that shape when it cannot read the upstream model's capability
metadata, which is exactly the case when AI Bridge sits between the client
and Bedrock.

This is the symmetric counterpart to the adaptive -> enabled conversion
added in coder/aibridge#225 for older Bedrock models. The new conversion is
gated on a bedrockModelRequiresAdaptiveThinking helper that matches Opus
4.7 model IDs (and ARN-style application inference profile names that
include the model ID).

The effort level is derived from the original budget_tokens / max_tokens
ratio using the midpoints of the forward mapping's anchor ratios, so a
payload that round-trips through both conversions lands on the same effort
level it started with. An explicit output_config.effort already present in
the request is preserved.

Adaptive-only models support output_config natively (no beta flag), so the
field-strip pass is updated to exempt output_config for those models via a
new variadic exemptFields parameter on removeUnsupportedBedrockFields.

Fixes coder/aibridge#280
dannykopping added a commit to coder/coder that referenced this pull request May 15, 2026
…e for Bedrock Opus 4.7+ (#25335)

*Disclaimer: implemented by a Coder Agent using Claude Opus 4.6/4.7*

Fixes
[coder/aibridge#280](coder/aibridge#280).

Claude Opus 4.7 (and future adaptive-only Bedrock models) reject the
legacy `thinking.type: "enabled"` + `budget_tokens` shape with a 400.
Claude Code falls back to that shape when it cannot read the upstream
model's capability metadata, which is exactly the case when AI Bridge
sits between the client and Bedrock. Pinning back to Opus 4.6 is the
only operator workaround today.

This is the counterpart to the `adaptive -> enabled` conversion added in
[coder/aibridge#225](coder/aibridge#225) for
older Bedrock models.

## Behavior

- New `bedrockModelRequiresAdaptiveThinking()` helper matches Opus 4.7
(covers `us.anthropic.claude-opus-4-7`, ARN-style application inference
profile names that include the model ID, etc.).
- New `RequestPayload.convertEnabledThinkingForBedrock()` rewrites
`thinking: {type: enabled, budget_tokens: N}` to `thinking: {type:
adaptive}`. The budget hint is dropped; an explicit
`output_config.effort` from the caller is preserved naturally because we
never touch that field. We deliberately do **not** derive an effort
label from the budget (see decision log).
- `removeUnsupportedBedrockFields` learns a variadic `exemptFields`
parameter. Adaptive-only models support `output_config` natively (no
beta flag required), so `augmentRequestForBedrock` exempts that field
for those models.
- Bedrock Opus 4.7 accepts `output_config.effort` but rejects
`output_config.format` (structured outputs) with the same "Extra inputs
are not permitted" 400. The generic strip pass operates at top-level
granularity only, so a small targeted pass drops `output_config.format`
after the top-level strip for adaptive-only models.

The whole Bedrock thinking-type shim block carries a header comment
flagging it as temporary; a planned native Bedrock provider removes the
impedance mismatch and lets us delete it.

## Out of scope

The issue calls out a possible follow-up around `Anthropic-Beta:
interleaved-thinking-2025-05-14` for adaptive-only models; best evidence
is that Opus 4.7 still accepts those flags, so this PR is a no-op there.

<details>
<summary>Decision log</summary>

- `bedrockModelSupportsAdaptiveThinking` now also returns `true` for
adaptive-only models. That keeps the existing
`convertAdaptiveThinkingForBedrock` branch from running on Opus 4.7
(which would otherwise be incorrect; `adaptive` is the supported native
type there), and the new `convertEnabledThinkingForBedrock` runs only
for adaptive-only models via the explicit
`bedrockModelRequiresAdaptiveThinking` switch case. The two model sets
are disjoint by construction.
- The reverse conversion does **not** derive `output_config.effort` from
`budget_tokens / max_tokens`. The two thinking shapes encode different
intents (`enabled+budget` is "give me exactly N tokens,"
`adaptive[+effort]` is "model, pick a budget, optionally biased") and
there is no canonical mapping between them. An earlier draft of this PR
derived effort via midpoints of an invented anchor table; it was
symmetric-looking but lossy and required a lot of scaffolding (sorted
anchors, init-time invariant guard, round-trip tests) to keep two halves
consistent. The reverse direction now just rewrites the shape, which is
honest about the information loss and matches platform-defined adaptive
behavior when no effort hint is present.
- `output_config.format` is stripped only for adaptive-only models.
Other Bedrock models either don't get `output_config` through at all
(top-level strip handles them) or accept it via a beta flag that may
imply broader feature support. Easy to widen if the same 400 shows up
elsewhere.
- I chose `variadic exemptFields ...string` over passing the model down
to `removeUnsupportedBedrockFields`, to keep that function focused on
stripping and to localise the model-aware policy in
`augmentRequestForBedrock`.

</details>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: Bedrock models that don't support adaptive thinking reject thinking.type: "adaptive" requests

2 participants